﻿using System.Data.Services.Providers;
using System.Linq.Expressions;
using System.Reflection;

namespace umbraco.DataServices.Query
{
    internal class PropertyTranslatingVisitor : ExpressionVisitor {

        internal static readonly MethodInfo GetValueMethodInfo = typeof(DataServiceProviderMethods).GetMethod("GetValue", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(object), typeof(ResourceProperty) }, null);
        internal static readonly MethodInfo GetSequenceValueMethodInfo = typeof(DataServiceProviderMethods).GetMethod("GetSequenceValue", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(object), typeof(ResourceProperty) }, null);
        internal static readonly MethodInfo ConvertMethodInfo = typeof(DataServiceProviderMethods).GetMethod("Convert", BindingFlags.Static | BindingFlags.Public);
        internal static readonly MethodInfo TypeIsMethodInfo = typeof(DataServiceProviderMethods).GetMethod("TypeIs", BindingFlags.Static | BindingFlags.Public);

        internal static Expression TranslateExpression(Expression expression) {
            var visitor = new PropertyTranslatingVisitor();
            return visitor.Visit(expression);
        }

        protected override Expression VisitMethodCall(MethodCallExpression m) {

            if (m.Method == GetValueMethodInfo)
                return Expression.Call(Visit(m.Arguments[0]), typeof(IDynamicProperty).GetMethod("GetPropertyValue"), Expression.Property(m.Arguments[1], "Name"));

            if (m.Method.IsGenericMethod && m.Method.GetGenericMethodDefinition() == GetSequenceValueMethodInfo)
                return Expression.Convert(Expression.Call(Visit(m.Arguments[0]), typeof(IDynamicProperty).GetMethod("GetPropertyValue"), Expression.Property(m.Arguments[1], "Name")), m.Method.ReturnType);

            if (m.Method == ConvertMethodInfo)
                return Visit(m.Arguments[0]);

            if (m.Method == TypeIsMethodInfo)
                return Expression.Equal(Expression.Property(Visit(m.Arguments[0]), typeof(IDynamicProperty).GetProperty("ResourceType")), m.Arguments[1]);

            return base.VisitMethodCall(m);

        }

    }
}
